package xendit

import (
	"encoding/json"
	"errors"
	"log/slog"
	"time"

	"gitee.com/gxcc/go-utils/utils"
)

/*************************************************************付款_start***********************************************************************/

// 接口具体详情见https://xendit.github.io/apireference/#create-charge
type ChargeRequest struct {
	TokenId          string `json:"token_id"`          // The token ID used to charge the card.
	ExternalId       string `json:"external_id"`       // A unique identifier of your choice. Max 64 characters. (在我们这是trans.Id)
	Amount           int64  `json:"amount"`            // The charge amount
	AuthenticationId string `json:"authentication_id"` // Authentication ID for authenticating charge. Optional only if charge was already authenticated with a single-use token, or if optional authentication is enabled for your account.
	CardCvn          string `json:"card_cvn"`          // 3 or 4 digit CVN (CVC) code. Optional but highly recommended. Required for cards issued in Europe.
	Capture          bool   `json:"capture"`           // Whether or not to capture immediately. default true.
	Descriptor       string `json:"descriptor"`        // Spesific descriptor to define merchant's identity
}

type ChargeResponse struct {
	Created               *time.Time `json:"created"`                 // An ISO timestamp that tracks when the charge was made.
	Status                string     `json:"status"`                  // Status of the charge. See Charge Statuses.
	BusinessId            string     `json:"business_id"`             // The ID of your business in Xendit.
	AuthorizedAmount      int64      `json:"authorized_amount"`       // The amount that've been authorized for this charge.
	ExternalId            string     `json:"external_id"`             // A unique identifier of your choice.
	MerchantId            string     `json:"merchant_id"`             // Your merchant ID used for processing credit cards with the bank.
	MerchantReferenceCode string     `json:"merchant_reference_code"` // An ID used to reconcile transactions with the bank.
	CardType              string     `json:"card_type"`               // Type of card (CREDIT or DEBIT)
	MaskedCardNumber      string     `json:"masked_card_number"`      // Masked card number. The first 6 digits are the BIN (Bank Identification Number).
	ChargeType            string     `json:"charge_type"`             // Types of charges. See Charge types.
	CardBrand             string     `json:"card_brand"`              // Card scheme (VISA, MASTERCARD,...)
	BankReconciliationId  string     `json:"bank_reconciliation_id"`  // ID of the transaction that can be reconciled with bank
	Eci                   string     `json:"eci"`                     // Status of 3DS authentication. See ECI codes.
	CaptureAmount         int64      `json:"capture_amount"`          // The amount that've been captured for this charge. Can be up to authorized_amount.
	Id                    string     `json:"id"`                      // ID of the charge captured.
	Descriptor            string     `json:"descriptor"`              // Description which already inputted by merchant when creating a charge.
	FailureReason         string     `json:"failure_reason"`          // If status is FAILED, this describes the failure. See Charge Failure Reasons.
}

func (ChargeResponse) TableName() string {
	return "xen_card_charge_response"
}

// 信用卡支付请求
func (svc *XenditSvc) Charge(tokenId string, externalId string, amount int64,
	authenticationId string, cardCvn string, descriptor string) (ChargeResponse, error) {
	var params = ChargeRequest{
		TokenId:          tokenId,
		ExternalId:       externalId,
		Amount:           amount,
		AuthenticationId: authenticationId,
		Capture:          true,
		CardCvn:          cardCvn,
		Descriptor:       descriptor,
	}
	url := "https://api.xendit.co/credit_card_charges"
	headers := map[string]string{
		"Content-Type":  "application/json",
		"Authorization": svc.ApiKey,
	}

	req, err := json.Marshal(params)
	if err != nil {
		return ChargeResponse{}, errors.New("charge failed")
	}

	res, err := utils.HttpPost(url, headers, req)
	if err != nil {
		return ChargeResponse{}, errors.New("charge failed")
	}

	resMap := make(map[string]string)
	if err := json.Unmarshal(res.Body, &resMap); err != nil {
		slog.Error(err.Error())
		return ChargeResponse{}, err
	}

	slog.Info("credit card charge result: " + string(res.Body))

	if len(resMap["error_code"]) > 0 {
		slog.Error("credit card charge error: " + resMap["error_code"])
		return ChargeResponse{}, errors.New(resMap["error_code"])
	}
	var response ChargeResponse
	if err := json.Unmarshal(res.Body, &response); err != nil {
		slog.Error(err.Error())
		return ChargeResponse{}, err
	}
	if response.Status != "AUTHORIZED" && response.Status != "CAPTURED" {
		slog.Error("credit card charge failed: " + response.FailureReason)
		return response, errors.New(response.FailureReason)
	}

	return response, nil
}

/*************************************************************付款_end***********************************************************************/

/*************************************************************退款_start***********************************************************************/

// 接口具体详情见https://xendit.github.io/apireference/?bash#create-refund
type RefundResponse struct {
	Updated            *time.Time `json:"updated"`
	Created            *time.Time `json:"created"`
	CreditCardChargeId string     `json:"credit_card_charge_id"`
	UserId             string     `json:"user_id"` // Your ID in xendit system
	Amount             int64      `json:"amount"`  // Amount of the refund
	ExternalId         string     `json:"external_id"`
	Status             string     `json:"status"`
	FailureReason      string     `json:"failure_reason"`
	FeeRefundAmount    int64      `json:"fee_refund_amount"` // Amount of fee refunded (proportional to the refund amount)
	Id                 string     `json:"id"`
}

func (RefundResponse) TableName() string {
	return "xen_card_refund_response"
}

// 信用卡退款请求
func (svc *XenditSvc) Refund(creditCardChargeId string, externalId string, amount int64) (RefundResponse, error) {
	var params = map[string]any{
		"amount":      amount,
		"external_id": externalId,
	}
	url := "https://api.xendit.co/credit_card_charges/" + creditCardChargeId + "/refunds"
	headers := map[string]string{
		"x-api-version": "2019-05-01",
		"Content-Type":  "application/json",
		"Authorization": svc.ApiKey,
	}

	req, err := json.Marshal(params)
	if err != nil {
		return RefundResponse{}, errors.New("refund failed")
	}

	res, err := utils.HttpPost(url, headers, req)
	if err != nil {
		return RefundResponse{}, errors.New("refund failed")
	}

	resMap := make(map[string]string)
	if err := json.Unmarshal(res.Body, &resMap); err != nil {
		slog.Error(err.Error())
		return RefundResponse{}, err
	}
	if len(resMap["error_code"]) > 0 {
		slog.Error("credit card refund failed: " + resMap["error_code"])
		return RefundResponse{}, errors.New(resMap["error_code"])
	}
	var response RefundResponse
	if err := json.Unmarshal(res.Body, &response); err != nil {
		slog.Error(err.Error())
		return RefundResponse{}, err
	}
	if response.Status != "REQUESTED" {
		slog.Error("credit card refund failed: " + response.FailureReason)
		return response, errors.New(response.FailureReason)
	}

	//if err := app.DB.Create(&response).Error; err != nil {
	//	app.LogInfo("保存xendit退款通知失败, response:" + string(res.Body))
	//}

	return response, nil
}

/*************************************************************退款_end***********************************************************************/
